package com.price.util

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.net.toUri
import com.price.common.extend.context
import com.price.common.extend.logError
import java.io.File
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine


object ApkInstallCompat {

    fun isInstall(packName:String):Boolean{
        var packageInfo: PackageInfo?
        try {
            packageInfo = context.packageManager.getPackageInfo(packName, 0)
        } catch (e: PackageManager.NameNotFoundException) {
            return false
        }
        return packageInfo != null
    }

    suspend fun openApk(path: String): Boolean = suspendCoroutine { cont ->
        try {
            val uri = path.toUri()
            val intent = Intent()
            intent.action = Intent.ACTION_VIEW
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.setDataAndType(uri, "application/vnd.android.package-archive")
            context.startActivity(intent)
            cont.resume(true)
        } catch (e: Exception) {
            cont.resumeWithException(e)
        }
    }


    suspend fun install(
        apkFilePath: String,
        packageManager: PackageManager
    ): Boolean = suspendCoroutine { cont ->
        var session: PackageInstaller.Session? = null
        try {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                //as PackageInstaller was added in API 21, let's use the old way of doing it prior to 21
                val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
                val apkUri = apkFilePath.toUri()
                val appInfo = context.applicationInfo
                intent.data = apkUri
                intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
                intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
                intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
                intent.putExtra(
                    Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                    appInfo.packageName
                )
                context.startActivity(intent)
                cont.resume(true)
            } else {
                // API level 21 or higher, we need to use PackageInstaller
                val apkFile = File(apkFilePath)
                val packageInstaller = packageManager.packageInstaller
                val sessionParams = SessionParams(SessionParams.MODE_FULL_INSTALL)
                sessionParams.setSize(apkFile.length())
                val sessionId = createSession(packageInstaller, sessionParams)
                logError("install path:$apkFilePath ::: sessionId:$sessionId")
                if (sessionId != -1) {
                    session = packageInstaller.openSession(sessionId)

                    // Create an install status receiver.
                    val packageInSession = session.openWrite("package", 0, -1)

                    val fio = apkFile.inputStream()
                    val buffer = ByteArray(1024)
                    var n: Int
                    while (fio.read(buffer).also { n = it } >= 0) {
                        packageInSession.write(buffer, 0, n)
                    }

                    packageInSession.close() //need to close this stream

                    fio.close()
                    val intent = Intent(
                        context,
                        InstallResultReceiver::class.java
                    )

                    val pendingIntent =
                        PendingIntent.getBroadcast(
                            context,
                            1,
                            intent,
                            PendingIntent.FLAG_UPDATE_CURRENT
                        )
                    session.commit(pendingIntent.intentSender)
                }
            }
            cont.resume(true)
        } catch (e: IOException) {
            e.printStackTrace()
            cont.resumeWithException(e)
        } finally {
            session?.abandon()
        }
    }
}

private fun createSession(
    packageInstaller: PackageInstaller,
    sessionParams: SessionParams
): Int {
    var sessionId = -1
    try {
        sessionId = packageInstaller.createSession(sessionParams)
    } catch (e: IOException) {
        e.printStackTrace()
    }
    return sessionId
}
